package com.smart.terminal.service;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.smart.common.utils.StringUtil;
import com.smart.entity.terminal.SshEntity;
import com.smart.model.exception.SmartException;
import com.smart.model.terminal.SshRequestVO;
import com.smart.mybatis.service.impl.BaseServiceImpl;
import com.smart.service.terminal.SshService;
import com.smart.terminal.dao.SshDao;
import com.smart.terminal.ftp.SftpFactory;
import com.smart.terminal.ftp.SftpGenericObjectPool;
import com.smart.terminal.utils.SftpUtil;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.text.Collator;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 终端 ServiceImpl
 *
 * @author wf
 * @since 2022-11-08 10:52:46
 */
@Service("sshService")
@Transactional(rollbackFor = Exception.class)
public class SshServiceImpl extends BaseServiceImpl<SshDao, SshEntity> implements SshService {
    @Autowired
    GenericObjectPoolConfig<ChannelSftp> sftpPoolConfig;
    @Autowired
    GenericObjectPoolConfig<ChannelExec> execPoolConfig;

    @Override
    @Cacheable(cacheNames = "ssh", key = "#id", unless = "#result == null")
    public SshEntity get(String id) {
        return super.get(id);
    }

    @Override
    @CachePut(cacheNames = "ssh", key = "#entity.id", unless = "#result == null")
    public SshEntity updateEntity(SshEntity entity) {
        return super.updateEntity(entity);
    }

    /**
     * 上传文件到服务器
     *
     * @param sshRequestVO – 请求模型
     */
    @Override
    public void upload(SshRequestVO sshRequestVO) {
        SshEntity sshEntity = get(sshRequestVO.getSshId());
        if (sshEntity == null) {
            throw new SmartException("终端不存在！");
        }
        // 创建工厂对象
        SftpFactory factory = new SftpFactory(
                sshEntity.getHost(),
                sshEntity.getPort(),
                sshEntity.getUsername(),
                sshEntity.getPassword());
        // 创建ftp工具对象
        SftpUtil sftpUtil = new SftpUtil(new SftpGenericObjectPool(factory, sftpPoolConfig));
        try {
            MultipartFile file = sshRequestVO.getFile();
            InputStream in = new ByteArrayInputStream(file.getBytes());
            sftpUtil.upload(sshRequestVO.getPath() + "/", file.getOriginalFilename(), in);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 上传文件到服务器
     *
     * @param sshRequestVO 请求模型
     * @return InputStream
     */
    @Override
    public InputStream download(SshRequestVO sshRequestVO) {
        if (StringUtil.isBlank(sshRequestVO.getSshId())) {
            throw new SmartException("参数错误！");
        }
        SshEntity sshEntity = get(sshRequestVO.getSshId());
        if (sshEntity == null) {
            throw new SmartException("终端不存在！");
        }
        try {
            // 创建SFTP工厂对象
            SftpFactory factory = new SftpFactory(
                    sshEntity.getHost(),
                    sshEntity.getPort(),
                    sshEntity.getUsername(),
                    sshEntity.getPassword());
            // 创建ftp工具对象
            SftpUtil sftpUtil = new SftpUtil(new SftpGenericObjectPool(factory, sftpPoolConfig));
            return sftpUtil.download(sshRequestVO.getPath(), sshRequestVO.getFileName());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取文件目录
     *
     * @param sshRequestVO 请求模型
     * @return String
     */
    @Override
    public List<Map<String, Object>> dir(SshRequestVO sshRequestVO) {
        if (StringUtil.isBlank(sshRequestVO.getSshId()) || sshRequestVO.getLevel() == null) {
            throw new SmartException("参数错误！");
        }
        SshEntity sshEntity = get(sshRequestVO.getSshId());
        if (sshEntity == null) {
            throw new SmartException("终端不存在！");
        }
        try {
            // 创建SFTP工厂对象
            SftpFactory factory = new SftpFactory(
                    sshEntity.getHost(),
                    sshEntity.getPort(),
                    sshEntity.getUsername(),
                    sshEntity.getPassword());
            // 创建ftp工具对象
            SftpUtil sftpUtil = new SftpUtil(new SftpGenericObjectPool(factory, sftpPoolConfig));
            //查看全部文件夹名称
            List<Map<String, Object>> dirList = new ArrayList<>();
            List<Map<String, Object>> fileList = new ArrayList<>();
            Vector<ChannelSftp.LsEntry> vector = sftpUtil.getDir(sshRequestVO.getPath());
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            for (int i = 0; i < vector.size(); i++) {
                ChannelSftp.LsEntry entry = vector.get(i);
                Map<String, Object> map = new HashMap<>(0);
                final String filename = entry.getFilename();
                map.put("title", filename);

                map.put("permission", entry.getAttrs().getPermissionsString());
                String key = String.valueOf(i);
                if (StringUtil.isNotBlank(sshRequestVO.getKey())) {
                    key = sshRequestVO.getKey() + "-" + key;
                }
                map.put("key", key);
                String path = "/" + filename;
                if (!sshRequestVO.getPath().equals("/")) {
                    path = sshRequestVO.getPath() + path;
                }
                map.put("path", path);
                map.put("level", sshRequestVO.getLevel() + 1);
                Date millisecondDate = new Date(entry.getAttrs().getMTime() * 1000L);
                String time = formatter.format(millisecondDate);
                map.put("updateTime", time);
                if (".".equals(filename) || "..".equals(filename) || ".Recycle_bin".equals(filename)) {
                    continue;
                }
                boolean compressedFile = isCompressedFile(entry);
                map.put("compressedFile", compressedFile);
                if (!compressedFile && (entry.getAttrs().isDir() || entry.getAttrs().isChr() || entry.getAttrs().isBlk() || entry.getAttrs().isLink())) {
                    dirList.add(map);
                } else {
                    map.put("isLeaf", true);
                    long size = entry.getAttrs().getSize();
                    map.put("size", readableFileSize(size));
                    fileList.add(map);
                }
            }
            dirList.sort((o1, o2) -> {
                //获取中⽂环境
                Comparator<Object> com = Collator.getInstance(Locale.CHINA);
                return com.compare(o1.get("title"), o2.get("title"));
            });
            dirList.addAll(fileList);
            if (sshRequestVO.getInit()) {
                List<Map<String, Object>> res = new ArrayList<>();
                Map<String, Object> map = new HashMap<>(0);
                map.put("title", "/");
                map.put("path", "/");
                map.put("key", "top-0");
                map.put("level", 0);
                map.put("children", dirList);
                res.add(map);
                return res;
            }
            return dirList;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 删除文件
     *
     * @param sshRequestVO 请求模型
     */
    @Override
    public void del(SshRequestVO sshRequestVO) {
        if (StringUtil.isBlank(sshRequestVO.getSshId())) {
            throw new SmartException("参数错误！");
        }
        SshEntity sshEntity = get(sshRequestVO.getSshId());
        if (sshEntity == null) {
            throw new SmartException("终端不存在！");
        }
        try {
            // 创建SFTP工厂对象
            SftpFactory factory = new SftpFactory(
                    sshEntity.getHost(),
                    sshEntity.getPort(),
                    sshEntity.getUsername(),
                    sshEntity.getPassword());
            // 创建ftp工具对象
            SftpUtil sftpUtil = new SftpUtil(new SftpGenericObjectPool(factory, sftpPoolConfig));
            sftpUtil.delete(sshRequestVO.getPath(), sshRequestVO.getFileName());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 文件大小智能转换
     * 会将文件大小转换为最大满足单位
     *
     * @param size（文件大小，单位为B）
     * @return String
     */
    private String readableFileSize(long size) {
        if (size <= 0) {
            return "0";
        }
        final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};
        int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
        return new DecimalFormat("#,###.##").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
    }

    /**
     * 是否压缩包
     *
     * @param entry 参数0
     * @return boolean
     */
    public boolean isCompressedFile(ChannelSftp.LsEntry entry) {
        String filename = entry.getFilename();
        // 检查文件名是否以已知的压缩文件扩展名结尾
        return filename.endsWith(".zip") || filename.endsWith(".tar") ||
                filename.endsWith(".tar.gz") || filename.endsWith(".tgz") ||
                filename.endsWith(".tar.bz2") || filename.endsWith(".tbz2") ||
                filename.endsWith(".7z") || filename.endsWith(".rar") ||
                filename.endsWith(".gz");
    }
}